package org.Keks;

import java.awt.AlphaComposite;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.Keks.graphics.KeksScreen;
import org.Keks.input.KeksInputHandler;
import org.Keks.input.KeksKeys;

public class KeksGame extends Component implements Runnable {
	private static final long serialVersionUID = 1L;

	public static int GAME_WIDTH = 512;
	public static int GAME_HEIGHT = 320;
	public static int GAME_SCALE = 1;

	public static Point SCREENXY = new Point();
	
	private boolean running = true;
	private int fps = 60;
	
	public static KeksKeys keys = new KeksKeys();
	public static KeksMap gamemap = null;
	public static KeksScreen screen = new KeksScreen(GAME_WIDTH, GAME_HEIGHT);
	
	public KeksGame() {		
		//Double the fun.
		
		this.addKeyListener(new KeksInputHandler(keys));
	}
	
	public Dimension getPreferredSize() {
		return new Dimension(GAME_WIDTH * GAME_SCALE, GAME_HEIGHT * GAME_SCALE);
	}

	/*public static void main(String[] args) {
		KeksGame sb = new KeksGame();
		JFrame frame = new JFrame();
		gamemap = new KeksMap(keys, (Canvas)sb);

		//Main method where a JFrame is created that contains our canvas.
		frame.add(sb, 0);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setResizable(false);
		frame.setVisible(true);
		frame.pack();
		frame.setLocationRelativeTo(null);
		sb.start();
	}*/

	public void run() {
		long lastTime = System.nanoTime();
		double unprocessed = 0;
		int frames = 0;
		long lastTimer1 = System.currentTimeMillis();

		try {
			init();
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}

		int toTick = 0;

		long lastRenderTime = System.nanoTime();
		int min = 999999999;
		int max = 0;

		while (running) {
			if (!this.hasFocus()) {
				keys.release();
			}

			double nsPerTick = 1000000000.0 / 60;//60 = framerate
			boolean shouldRender = false;
			while (unprocessed >= 1) {
				toTick++;
				unprocessed -= 1;
			}

			int tickCount = toTick;
			if (toTick > 0 && toTick < 3) {
				tickCount = 1;
			}
			if (toTick > 20) {
				toTick = 20;
			}

			for (int i = 0; i < tickCount; i++) {
				toTick--;
				tick();
				shouldRender = true;
			}

			/*BufferStrategy bs = getBufferStrategy();
			if (bs == null) {
				createBufferStrategy(3);
				continue;
			}
			if (shouldRender) {
				frames++;
				Graphics g = getDrawGraphics();
				render(g);
				
				long renderTime = System.nanoTime();
				int timePassed = (int) (renderTime - lastRenderTime);
				if (timePassed < min) {
					min = timePassed;
				}
				if (timePassed > max) {
					max = timePassed;
				}
				lastRenderTime = renderTime;
			}

			long now = System.nanoTime();
			unprocessed += (now - lastTime) / nsPerTick;
			lastTime = now;

			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			if (shouldRender) {
				if (bs != null) {
					bs.show();
				}
			}*/

			if (System.currentTimeMillis() - lastTimer1 > 1000) {
				lastTimer1 += 1000;
				fps = frames;
				frames = 0;
			}
		}
	}
	
	/**
	 * Method which is called every frame. Must contain tick() from Map class.
	 */
	public void tick() {
		keys.tick();//Essential for keys in Map class
		gamemap.tick();
		SCREENXY = getScreenXY();//Update screen position to translate mouse position correctly.
	}
	
	public void init() {
		setFocusTraversalKeysEnabled(false);
		requestFocus();
	}
	
	public void start() {
		running = true;
		Thread th = new Thread(this);
		th.setPriority(Thread.MAX_PRIORITY);
		th.start();
	}
	
	public void stop() {
		running = false;
	}
	
	public void paint(Graphics g) {
		//Stop flickering
		Graphics2D g2 = (Graphics2D) g;
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, getWidth(), getHeight());
		g.translate((getWidth() - GAME_WIDTH * GAME_SCALE) / 2, (getHeight() - GAME_HEIGHT * GAME_SCALE) / 2);
		g.clipRect(0, 0, GAME_WIDTH * GAME_SCALE, GAME_HEIGHT * GAME_SCALE);
		//Attention: You might want to call render(Screen screen) before g.drawImage!
		gamemap.render(screen);
		//Font.draw(screen, "FPS:" + fps, 5, 5);
		g.drawImage(screen.image, 0, 0, GAME_WIDTH * GAME_SCALE, GAME_HEIGHT * GAME_SCALE, null);
	}
	
	public Point getScreenXY() {
		return this.getLocationOnScreen();
	}
}
